using System;
using Microsoft.SPOT;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer;
using Gadgeteer.Interfaces;
using System.Threading;

namespace Dairy_Town
{
    class WifiAdapter
    {
        public GT.Timer scannerTimer;
        private GTM.GHIElectronics.WiFi_RS21 wifi;

        private int attempts        = 0;
        private int shortInterval   = 6000 * 5;
        private int longInterval    = 6000 * 60;

#error Values for "apSSID" and "apPassphrase" must be updated in config.xml, this error may be deleted once configured.
        private string myAccessPoint = ConfigurationManager.GetAppSetting("apSSID");
        private string myAP_Passphrase = ConfigurationManager.GetAppSetting("apPassphrase");

        public string IPAddress
        {
            get
            {
                return this.wifi.NetworkSettings.IPAddress;
            }
        }

        public event EventHandler GatewayAvailable;

        private void init(int interval)
        {
            if (scannerTimer != null)
            {
                scannerTimer.Stop();
            }
            
            scannerTimer = new GT.Timer(interval);
            scannerTimer.Tick += scannerTimer_Tick;
            scannerTimer.Start();
        }

        public WifiAdapter(GTM.GHIElectronics.WiFi_RS21 instance)
        {
            this.wifi = instance;

            this.wifi.NetworkDown += wifi_NetworkDown;
            this.wifi.NetworkUp += wifi_NetworkUp;
            this.wifi.NetworkSettings.EnableDynamicDns();
            this.wifi.NetworkSettings.EnableDhcp();
            this.wifi.UseDHCP();
            this.wifi.UseThisNetworkInterface(); // Tells Gadgeteer mainboard that this is the interface to use for network connections
            this.wifi.Interface.WirelessConnectivityChanged += Interface_WirelessConnectivityChanged;

            this.init(6000 * 2);
        }

        /// <summary>
        /// Scan for network at the timer tick
        /// </summary>
        /// <param name="timer"></param>
        void scannerTimer_Tick(GT.Timer timer)
        {
            Thread scanThread = new Thread(new ThreadStart(() =>
                {
                    this.Scan();
                }
            ));
            scanThread.Start();
        }

        void wifi_NetworkUp(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
        {
            //Console.Display("Wifi NetworkUp");

        }

        void wifi_NetworkDown(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
        {
            //Console.Display("Wifi NetworkDown");
        }

        void Interface_WirelessConnectivityChanged(object sender, GHI.Premium.Net.WiFiRS9110.WirelessConnectivityEventArgs e)
        {
            if (e.IsConnected)
            {
                //Console.Display("Wifi is connected");
            }
            else
            {
                //Console.Display("Wifi connection lost");
                this.init(shortInterval);
            }
        }

        public void ScanAll()
        {
            if (wifi.IsNetworkConnected)
            {
                //Console.Display("Already connected to network, aborting scan...");
                scannerTimer.Stop(); // We're already connected, stop future scans
                attempts = 0; // Reset our attempt counter
                return;
            }

            if (attempts >= 3)
            {
                this.init(longInterval); // If we havent' found the network after 3 attempts, increase the interval between scans to preserve processing power
            }

            try
            {
                this.wifi.UseDHCP(); // Enable DHCP to receive a network address
                GHI.Premium.Net.WiFiNetworkInfo[] scanNW = wifi.Interface.Scan(); // Scans for network and returns network info

                if(scanNW != null && scanNW.Length > 0)
                {
                    foreach (var network in scanNW)
                    {
                        if (network.SecMode != GHI.Premium.Net.SecurityMode.Open)
                            continue;

                        wifi.Interface.Join(network, "");

                        if (wifi.IsNetworkConnected)
                        {
                            this.GatewayAvailable(wifi, EventArgs.Empty);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Debug.Print(e.Message);
            }

            attempts++;
        }

        private bool CanReach(string url, UInt32 port=80)
        {
            return false;
        }

        public void Scan()
        {
            if (wifi.IsNetworkConnected)
            {
                //Console.Display("Already connected to network, aborting scan...");
                scannerTimer.Stop(); // We're already connected, stop future scans
                attempts = 0; // Reset our attempt counter
                return;
            }

            if (attempts >= 3)
            {
                this.init(longInterval); // If we havent' found the network after 3 attempts, increase the interval between scans to preserve processing power
            }
            
            try
            {
                this.wifi.UseDHCP(); // Enable DHCP to receive a network address
                GHI.Premium.Net.WiFiNetworkInfo[] scanNW = wifi.Interface.Scan(myAccessPoint); // Scans for specified network and returns network info

                if (scanNW != null && scanNW.Length > 0) // We make sure that network info exists, that the specified network was actually found
                {
                    //Console.Display("Connecting to " + myAccessPoint);
                    wifi.Interface.Join(scanNW[0], myAP_Passphrase); // Now that we've found the network, let's join it
                    if (wifi.IsNetworkConnected)
                    {
                        //Console.Display("IP Address " + wifi.NetworkSettings.IPAddress);
                        scannerTimer.Stop(); // We've connected to the network, we no longer need to scan for the network

                        this.GatewayAvailable(wifi, EventArgs.Empty);
                    }
                    else
                    {
                        //Console.Display("Network Not connected.");
                    }
                }
                else
                {
                    //Console.Display("Wifi connection Failed");
                }
            }
            catch (Exception e)
            {
                Debug.Print(e.Message);
            }

            attempts++;
        }
    }
}
